﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using EasyHook;
using System.Runtime.InteropServices;

namespace MalMonInject
{
    public class FileActivities:ActivityMonitor
    {
        LocalHook CreateFileHook;
        LocalHook ReadFileHook;
        LocalHook WriteFileHook;

        private DReadFile ReadFileFunc;

        public FileActivities(MalMonInject Injector):base(Injector)
        {
        }

        
        public override void InstallHook()
        {
            CreateFileHook = LocalHook.Create(
                    LocalHook.GetProcAddress("kernel32.dll", "CreateFileW"),
                    new DCreateFile(CreateFile_Hooked),
                    this.Injector);
            ReadFileHook = LocalHook.Create(
                    LocalHook.GetProcAddress("kernel32.dll", "ReadFile"),
                    new DReadFile(ReadFile_Hooked),
                    this.Injector);

            WriteFileHook = LocalHook.Create(
                    LocalHook.GetProcAddress("kernel32.dll", "WriteFile"),
                    new DWriteFile(WriteFile_Hooked),
                    this.Injector);

            CreateFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
            WriteFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });
            ReadFileHook.ThreadACL.SetExclusiveACL(new Int32[] { 0 });

            ReadFileFunc = LocalHook.GetProcDelegate<DReadFile>("kernel32.dll", "ReadFile");

        }

        /*CreateFile-----------------------------------------------------------------*/
        [UnmanagedFunctionPointer(CallingConvention.StdCall,
             CharSet = CharSet.Unicode,
             SetLastError = true)]
        delegate IntPtr DCreateFile(
            String InFileName,
            UInt32 InDesiredAccess,
            UInt32 InShareMode,
            IntPtr InSecurityAttributes,
            UInt32 InCreationDisposition,
            UInt32 InFlagsAndAttributes,
            IntPtr InTemplateFile);

        // just use a P-Invoke implementation to get native API access from C# (this step is not necessary for C++.NET)
        [DllImport("kernel32.dll",
            CharSet = CharSet.Unicode,
            SetLastError = true,
            CallingConvention = CallingConvention.StdCall)]
        static extern IntPtr CreateFile(
            String InFileName,
            UInt32 InDesiredAccess,
            UInt32 InShareMode,
            IntPtr InSecurityAttributes,
            UInt32 InCreationDisposition,
            UInt32 InFlagsAndAttributes,
            IntPtr InTemplateFile);

        // this is where we are intercepting all file accesses!
        static IntPtr CreateFile_Hooked(
            String InFileName,
            UInt32 InDesiredAccess,
            UInt32 InShareMode,
            IntPtr InSecurityAttributes,
            UInt32 InCreationDisposition,
            UInt32 InFlagsAndAttributes,
            IntPtr InTemplateFile)
        {

            try
            {
                MalMonInject This = (MalMonInject)HookRuntimeInfo.Callback;

                lock (This.Queue)
                {
                    //Time + Pid + Tid + Api + Content
                    This.Queue.Push(ActivityMonitor.FormatMessage(DateTime.Now, "CreateFile", InFileName));
                }
            }
            catch
            {
            }

            // call original API...
            return CreateFile(
                InFileName,
                InDesiredAccess,
                InShareMode,
                InSecurityAttributes,
                InCreationDisposition,
                InFlagsAndAttributes,
                InTemplateFile);
        }

        /*----code generated by script CodeGenerator.py----*/
        /*----ReadFile----*/
        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate bool DReadFile(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, IntPtr lpNumberOfBytesRead, IntPtr lpOverlapped);
        [DllImportAttribute("kernel32.dll", EntryPoint = "ReadFile")]
        [return: MarshalAsAttribute(UnmanagedType.Bool)]
        static extern bool ReadFile([InAttribute()] IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, IntPtr lpNumberOfBytesRead, IntPtr lpOverlapped);

        static bool ReadFile_Hooked(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToRead, IntPtr lpNumberOfBytesRead, IntPtr lpOverlapped)
        {
            bool res = false;
            try
            {
                MalMonInject This = (MalMonInject)HookRuntimeInfo.Callback;
                res = This.FileApis.ReadFileFunc(hFile, lpBuffer, nNumberOfBytesToRead, lpNumberOfBytesRead, lpOverlapped);

                lock (This.Queue)
                {
                    This.Queue.Push(ActivityMonitor.FormatMessage(DateTime.Now, "ReadFile", Marshal.PtrToStringAnsi(lpBuffer)));
                }
            }
            catch
            {

            }
            return res;

        }

        /*----code generated by script CodeGenerator.py----*/
        /*----WriteFile----*/
        [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode, SetLastError = true)]
        delegate bool DWriteFile(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToWrite, IntPtr lpNumberOfBytesWritten, IntPtr lpOverlapped);
        [DllImportAttribute("kernel32.dll", EntryPoint = "WriteFile")]
        [return: MarshalAsAttribute(UnmanagedType.Bool)]
        static extern bool WriteFile([InAttribute()] IntPtr hFile, [InAttribute()] IntPtr lpBuffer, uint nNumberOfBytesToWrite, IntPtr lpNumberOfBytesWritten, IntPtr lpOverlapped);

        static bool WriteFile_Hooked(IntPtr hFile, IntPtr lpBuffer, uint nNumberOfBytesToWrite, IntPtr lpNumberOfBytesWritten, IntPtr lpOverlapped)
        {
            try
            {
                MalMonInject This = (MalMonInject)HookRuntimeInfo.Callback;

                lock (This.Queue)
                {
                    This.Queue.Push(ActivityMonitor.FormatMessage(DateTime.Now, "WriteFile", Marshal.PtrToStringAnsi(lpBuffer)));
                }

            }
            catch
            {

            }
            return WriteFile(hFile, lpBuffer, nNumberOfBytesToWrite, lpNumberOfBytesWritten, lpOverlapped);
        }


    }
}
